<script setup lang="ts">
import { computed, onMounted, watch, nextTick, ref, onUnmounted } from 'vue';
import html2canvas from 'html2canvas';
import { Message, User } from '../../types';
import { useI18n } from 'vue-i18n';
import MarkdownIt from 'markdown-it';
import mermaid from 'mermaid';
import hljs from 'highlight.js';
import 'highlight.js/styles/github.css';
import { copyToClipboard } from '../../utils/clipboard';
import { ToastService } from '../../utils/toastService';
import { useChatStore } from '../../stores/chatStore';

const { t } = useI18n<{ message: typeof import('../../locales/en-US').default }>();
const chatStore = useChatStore();

const props = defineProps<{
  message: Message;
  isCurrentUser: boolean;
  sender?: User;
  index: number;
  isSelected: boolean;
  isComplete: boolean; // 控制 mermaid 图表的渲染时机
  totalMessages?: number; // 消息总数，用于判断是否是最后一条消息
}>();

const emit = defineEmits<{
  (e: 'toggle-select', index: number): void;
  (e: 'show-mindmap', code: string): void;
  (e: 'regenerate'): void;
}>();

const isHovered = ref(false);
const copySuccess = ref(false);
const messageRef = ref<HTMLElement | null>(null);

// 初始化markdown解析器
const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight: (str, lang) => {
    if (lang && lang === 'mermaid') {
      // 检测是否为mindmap类型
      const isMindMap = str.trim().startsWith('mindmap');
      
      // 添加代码块标题栏（显示语言类型和复制按钮，对mindmap类型添加运行按钮）
      return `<div class="code-block"><div class="code-header"><div class="header-left"><button class="toggle-button" aria-label="Toggle code block" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></button><span class="language-label">mermaid${isMindMap ? ' (mindmap)' : ''}</span></div><div class="header-right">${isMindMap ? '<button class="run-button" aria-label="Run mindmap" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg><span>Run</span></button>' : ''}<button class="copy-button" aria-label="Copy code" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg><span>Copy</span></button></div></div><pre class="hljs-pre expanded"><code class="mermaid" data-is-mindmap="${isMindMap}" data-original-code="${encodeURIComponent(str)}" data-pending="true"><div class="mermaid-placeholder">图表准备中...</div>${str}</code></pre></div>`;
    }
    
    let codeContent = '';
    let language = lang || '';
    
    if (lang && hljs.getLanguage(lang)) {
      try {
        codeContent = hljs.highlight(str, { language: lang }).value;
      } catch (__) {
        codeContent = md.utils.escapeHtml(str);
      }
    } else {
      codeContent = md.utils.escapeHtml(str);
    }
    
    // 添加代码块标题栏（显示语言类型和复制按钮）    
    return`<div class="code-block"><div class="code-header"><div class="header-left"><button class="toggle-button" aria-label="Toggle code block" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></button><span class="language-label">${language||'text'}</span></div><button class="copy-button" aria-label="Copy code" type="button"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg><span>Copy</span></button></div><pre class="hljs-pre expanded"><code class="hljs language-${language}">${codeContent}</code></pre></div>`;
  }
});

// 检测是否包含思考内容
const hasThinkContent = computed(() => {
  if (!props.message?.content) return false;
  return props.message.content.includes('<think>') && props.message.content.includes('</think>');
});

// 提取思考内容
const thinkContent = computed(() => {
  if (!hasThinkContent.value) return '';
  try {
    const match = props.message.content.match(/<think>([\s\S]*?)<\/think>/);
    return match ? match[1].trim() : '';
  } catch (error) {
    console.error('Error extracting think content:', error);
    return '';
  }
});

// 移除思考标签后的内容
const contentWithoutThink = computed(() => {
  if (!hasThinkContent.value) return props.message.content;
  try {
    return props.message.content.replace(/<think>[\s\S]*?<\/think>/, '').trim();
  } catch (error) {
    console.error('Error removing think content:', error);
    return props.message.content;
  }
});

// 控制思考内容的显示状态
const isThinkExpanded = ref(false);

// 控制引用文件列表的显示状态
const isSourceListExpanded = ref(false);

// 检查是否有引用文件列表
const hasContentSourceList = computed(() => {
  return props.message.contentSourceList && props.message.contentSourceList.length > 0;
});

// 切换引用文件列表的显示状态
function toggleSourceList() {
  isSourceListExpanded.value = !isSourceListExpanded.value;
}

// 切换思考内容的显示状态
function toggleThinkContent() {
  isThinkExpanded.value = !isThinkExpanded.value;
}

// 渲染后的HTML内容
const renderedContent = computed(() => {
  if (!props.message?.content) return '';
  try { 
    // 如果有思考内容，只渲染非思考部分
    const contentToRender = hasThinkContent.value ? contentWithoutThink.value : props.message.content;
    
    
    
    // 默认渲染markdown
    return md.render(contentToRender);
  } catch (error) {
    console.error('Error rendering markdown:', error);
    return props.message.content;
  }
});

// 是否显示重新生成按钮
const showRegenerateButton = computed(() => {
  // 当消息是AI助手发送的，且消息已完成生成时，且是最后一条消息时显示重新生成按钮
  return !props.isCurrentUser && 
         props.isComplete && 
         props.message.senderId === 'assistant' && 
         (props.totalMessages === undefined || props.index === props.totalMessages - 1);
});

// 处理重新生成
function handleRegenerate() {
  emit('regenerate');
}

// 将mermaid图表转换为图片
async function convertMermaidToImage(mermaidElement: HTMLElement): Promise<string> {
  try {
    const canvas = await html2canvas(mermaidElement, {
      backgroundColor: null,
      scale: 2,
      // 强制固定尺寸
      width: 800,
      height: 600,
      windowWidth: 800,
      windowHeight: 600,
      logging: false,
      useCORS: true
    });
    return canvas.toDataURL('image/png');
  } catch (error) {
    console.error('转换mermaid图表失败:', error);
    return '';
  }
}

// 处理消息选择
async function handleSelect() {
  try {
    // 检查是否有mermaid图表
    const mermaidElements = messageRef.value?.querySelectorAll('.mermaid');
    if (mermaidElements && mermaidElements.length > 0) {
      // 转换所有mermaid图表为图片
      for (const element of mermaidElements) {
        const imgData = await convertMermaidToImage(element as HTMLElement);
        if (imgData) {
          const img = document.createElement('img');
          img.src = imgData;
          img.style.maxWidth = '100%';
          img.style.width = '800px';
          img.style.margin = '0 auto';
          img.style.display = 'block';
          img.alt = 'Mermaid Chart';
          element.replaceWith(img);
        }
      }
    }
    emit('toggle-select', props.index);
  } catch (error) {
    console.error('处理预览失败:', error);
    emit('toggle-select', props.index);
  }
}


// 复制整个消息内容
async function handleCopyMessage() {
  try {
    // 获取要复制的内容，优先使用纯文本内容
    const contentToCopy = props.message.content || '';
    
    // 尝试复制到剪贴板
    await copyToClipboard(contentToCopy);
    
    // 复制成功
    copySuccess.value = true;
    ToastService.success('复制成功');
    
    // 2秒后重置状态
    setTimeout(() => {
      copySuccess.value = false;
    }, 2000);
  } catch (error) {
    // 复制失败
    console.error('复制失败:', error);
    copySuccess.value = false;
    ToastService.error('复制失败，请重试');
  }
}

// 渲染Mermaid图表
// 为mermaid图表生成唯一ID
const generateMermaidId = (index: number) => `mermaid-${props.index}-${index}`;

// 存储mermaid渲染定时器
let mermaidRenderTimer: number | null = null;

// 跟踪mermaid渲染状态
const isMermaidRendering = ref(false);

// 优化后的mermaid渲染函数
const renderMermaid = () => {
  if (isMermaidRendering.value) return;
  
  try {
    isMermaidRendering.value = true;
    
    // 清除之前的定时器
    if (mermaidRenderTimer) {
      clearTimeout(mermaidRenderTimer);
      mermaidRenderTimer = null;
    }

    nextTick(() => {
      const mermaidElements = messageRef.value?.querySelectorAll('.mermaid');
      if (mermaidElements && mermaidElements.length > 0) {
        // 为每个mermaid元素添加唯一ID
        mermaidElements.forEach((el, index) => {
          try {
            const id = generateMermaidId(index);
            el.id = id;
          } catch (error) {
            console.error('为mermaid元素设置ID失败:', error);
          }
        });
        
        // 使用防抖避免频繁重绘 (300ms防抖)
        mermaidRenderTimer = window.setTimeout(() => {
          try {
            // 检查消息是否完成，只有完成时才渲染mermaid图表
            if (props.isComplete) {
              // 先尝试销毁之前的mermaid实例
              try {
                mermaidElements.forEach(el => {
                  const svg = el.querySelector('svg');
                  if (svg) {
                    svg.remove();
                  }
                  
                  // 移除占位符
                  const placeholder = el.querySelector('.mermaid-placeholder');
                  if (placeholder) {
                    placeholder.remove();
                  }
                  
                  // 移除pending标记
                  el.removeAttribute('data-pending');
                });
              } catch (cleanupError) {
                console.warn('清理mermaid图表失败:', cleanupError);
              }

              // 渲染新的mermaid图表
              try {
                mermaid.run({
                  nodes: Array.from(mermaidElements) as HTMLElement[],
                }).catch(error => {
                  console.error('mermaid.run() 错误:', error);
                  // 显示错误占位符
                  mermaidElements.forEach(el => {
                    el.innerHTML = '<div class="mermaid-error">图表渲染失败</div>';
                  });
                });
              } catch (error) {
                console.error('mermaid.run() 异常:', error);
                // 显示错误占位符
                mermaidElements.forEach(el => {
                  el.innerHTML = '<div class="mermaid-error">图表渲染异常</div>';
                });
              }
            } else {
              console.log('消息尚未完成，跳过mermaid渲染');
            }
          } catch (error) {
            console.error('mermaid渲染失败:', error);
          } finally {
            isMermaidRendering.value = false;
          }
        }, 300);
      } else {
        isMermaidRendering.value = false;
      }
    });
  } catch (error) {
    console.error('mermaid渲染流程出错:', error);
    isMermaidRendering.value = false;
  }
};

// 组件卸载时清理
onUnmounted(() => {
  if (mermaidRenderTimer) {
    clearTimeout(mermaidRenderTimer);
  }
  cleanupEventListeners();
});

// 存储事件监听器引用
const eventListeners = new Map<Element, () => void>();

// 清理事件监听器
const cleanupEventListeners = () => {
  eventListeners.forEach((cleanup) => {
    try {
      cleanup();
    } catch (error) {
      console.error('清理事件监听器失败:', error);
    }
  });
  eventListeners.clear();
};

// 优化后的按钮事件监听设置
const setupButtons = () => {
  try {
    cleanupEventListeners();
    
    nextTick(() => {
      // 复制按钮事件监听
      const copyButtons = messageRef.value?.querySelectorAll('.copy-button');
      if (copyButtons) {
        copyButtons.forEach((button) => {
          try {
            const clickHandler = () => {
              try {
                const codeBlock = button.closest('.code-block');
                const code = codeBlock?.querySelector('code')?.textContent || '';
                
                copyToClipboard(code).then(() => {
                  const originalHTML = button.innerHTML;
                  button.innerHTML = `<span class="copied-text">✓ ${t('common.copied')}</span>`;
                  button.classList.add('copied');
                  
                  setTimeout(() => {
                    button.innerHTML = originalHTML;
                    button.classList.remove('copied');
                  }, 2000);
                }).catch(error => {
                  console.error('复制失败:', error);
                });
              } catch (error) {
                console.error('处理复制点击失败:', error);
              }
            };
            
            const cleanup = () => button.removeEventListener('click', clickHandler);
            button.addEventListener('click', clickHandler);
            eventListeners.set(button, cleanup);
          } catch (error) {
            console.error('绑定复制按钮事件失败:', error);
          }
        });
      }

      // 展开/收起按钮事件监听
      const toggleButtons = messageRef.value?.querySelectorAll('.toggle-button');
      if (toggleButtons) {
        toggleButtons.forEach((button) => {
          try {
            const clickHandler = () => {
              try {
                const codeBlock = button.closest('.code-block');
                const pre = codeBlock?.querySelector('.hljs-pre');
                if (pre) {
                  const isExpanded = pre.classList.contains('expanded');
                  pre.classList.toggle('expanded');
                  
                  const svg = button.querySelector('svg');
                  if (svg) {
                    svg.style.transform = isExpanded ? 'rotate(0deg)' : 'rotate(180deg)';
                  }
                }
              } catch (error) {
                console.error('处理展开/收起点击失败:', error);
              }
            };
            
            const cleanup = () => button.removeEventListener('click', clickHandler);
            button.addEventListener('click', clickHandler);
            eventListeners.set(button, cleanup);
          } catch (error) {
            console.error('绑定展开/收起按钮事件失败:', error);
          }
        });
      }

      // 运行按钮事件监听（用于mindmap）
      const runButtons = messageRef.value?.querySelectorAll('.run-button');
      if (runButtons) {
        runButtons.forEach((button) => {
          try {
            const clickHandler = () => {
              try {
                const codeBlock = button.closest('.code-block');
                const code = codeBlock?.querySelector('code');
                
                if (code && code.getAttribute('data-is-mindmap') === 'true') {
                  const encodedCode = code.getAttribute('data-original-code') || '';
                  const mindmapCode = encodedCode ? decodeURIComponent(encodedCode) : '';
                  
                  if (!mindmapCode.trim()) {
                    throw new Error('空的思维导图代码');
                  }
                  
                  // 触发show-mindmap事件
                  emit('show-mindmap', mindmapCode);
                  
                  // 添加按钮反馈效果
                  const originalHTML = button.innerHTML;
                  button.innerHTML = `<span class="copied-text">已打开</span>`;
                  
                  setTimeout(() => {
                    button.innerHTML = originalHTML;
                  }, 2000);
                }
              } catch (error) {
                console.error('处理运行mindmap点击失败:', error);
                const originalHTML = button.innerHTML;
                button.innerHTML = `<span class="copied-text">错误</span>`;
                
                setTimeout(() => {
                  button.innerHTML = originalHTML;
                }, 2000);
              }
            };
            
            const cleanup = () => button.removeEventListener('click', clickHandler);
            button.addEventListener('click', clickHandler);
            eventListeners.set(button, cleanup);
          } catch (error) {
            console.error('绑定运行按钮事件失败:', error);
          }
        });
      }
    });
  } catch (error) {
    console.error('设置按钮失败:', error);
  }
};

// 初始化Mermaid
onMounted(() => {
  try {
    mermaid.initialize({ 
      startOnLoad: false,
      theme: 'default',
      securityLevel: 'loose',
      // 强制设置图表大小
      htmlLabels: true,
      fontSize: 14,
      flowchart: {
        useMaxWidth: false,
        htmlLabels: true
      },
      er: {
        useMaxWidth: false
      },
      sequence: {
        useMaxWidth: false,
        width: 800
      },
      gantt: {
        useMaxWidth: false
      },
      journey: {
        useMaxWidth: false
      },
      pie: {
        useMaxWidth: false
      }
    });
    
    // 设置按钮事件监听
    setupButtons();
    
    // 只有当消息完成时才渲染mermaid图表
    if (props.isComplete) {
      renderMermaid();
    }
  } catch (error) {
    console.error('Mermaid初始化失败:', error);
  }
});

// 监听内容变化重新渲染图表和添加复制按钮
watch(renderedContent, () => {
  try {
    // 无论内容如何变化，都设置按钮
    setupButtons();
    
    // 只有当消息完成时才渲染mermaid图表
    if (props.isComplete) {
      renderMermaid();
    }
  } catch (error) {
    console.error('内容渲染失败:', error);
  }
});

// 监听isComplete属性变化
watch(() => props.isComplete, (newValue) => {
  if (newValue === true) {
    // 当消息完成时，渲染所有mermaid图表
    nextTick(() => {
      renderMermaid();
    });
  }
});

// 清理事件监听器
onUnmounted(() => {
  cleanupEventListeners();
});
</script>

<template>
  <div 
    class="message-bubble" 
    :class="{ 
      'user-message': isCurrentUser,
      'selected': isSelected 
    }"
    @mouseenter="isHovered = true"
    @mouseleave="isHovered = false"
  >
    <!-- 助手消息头像 -->
    <div v-if="!isCurrentUser" class="message-avatar">
      <div class="avatar-bg assistant-avatar-bg">
        <span class="avatar-text">AI</span>
      </div>
    </div>
    
    <div class="message-wrapper">
      <div 
        ref="messageRef"
        class="message-content markdown-body"
        :class="{ 'thinking': message.content === '思考中...' }"
      >
        <!-- 思考中状态显示 -->
        <template v-if="message.content === '思考中...'">
          <div class="thinking-indicator">
            <span class="thinking-text">思考中</span>
            <div class="thinking-dots">
              <span></span>
              <span></span>
              <span></span>
            </div>
          </div>
        </template>
        <!-- 正常内容显示 -->
        <template v-else>
          <!-- 思考内容展示 -->
          <div v-if="hasThinkContent && !isCurrentUser && message.senderId === 'assistant'" class="think-container">
            <div class="think-header" @click="toggleThinkContent">
              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" :style="{ transform: isThinkExpanded ? 'rotate(180deg)' : 'rotate(0deg)' }">
                <polyline points="6 9 12 15 18 9"></polyline>
              </svg>
              <span>{{ isThinkExpanded ? '收起思考过程' : '展开思考过程' }}</span>
            </div>
            <div v-if="isThinkExpanded" class="think-content">
              <pre>{{ thinkContent }}</pre>
            </div>
          </div>
          <div v-html="renderedContent"></div>
          
          <!-- 引用文件下拉窗口 -->
          <div v-if="hasContentSourceList" class="source-files-container">
            <div class="source-header" @click="toggleSourceList">
              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" :style="{ transform: isSourceListExpanded ? 'rotate(180deg)' : 'rotate(0deg)' }">
                <polyline points="6 9 12 15 18 9"></polyline>
              </svg>
              <span>{{ isSourceListExpanded ? '收起引用文件' : '查看引用文件' }}</span>
              <span class="source-count">({{ message.contentSourceList?.length || 0 }})</span>
            </div>
            <div v-if="isSourceListExpanded" class="source-list">
              <div v-for="(source, index) in message.contentSourceList" :key="index" class="source-item">
                <div class="file-download-link" @click="chatStore.handleFileDownload(source.fileId, source.fileName)">
                  <span class="file-icon">📄</span>
                  <span class="file-name">{{ source.fileName }}</span>
                  <span class="download-text">下载</span>
                </div>
              </div>
            </div>
          </div>
        </template>
      </div>
    </div>
    
    <!-- 用户消息头像 -->
    <div v-if="isCurrentUser" class="message-avatar user-avatar">
      <div class="avatar-bg user-avatar-bg">
        <span class="avatar-text">{{ sender?.nickname?.charAt(0).toUpperCase() || '👤' }}</span>
      </div>
    </div>
  </div>
  
  <div class="message-footer">
      <span class="timestamp">
        {{ new Date(message.timestamp).toLocaleTimeString() }}
      </span>
      
      <div 
        class="message-actions"
        :class="{ 'visible': isHovered || isSelected }"
      >
        <button 
          class="action-button preview-button"
          @click="handleSelect"
          :title="isSelected ? '取消预览' : '预览'"
        >
          <svg 
            xmlns="http://www.w3.org/2000/svg" 
            width="16" 
            height="16" 
            viewBox="0 0 24 24" 
            fill="none" 
            stroke="currentColor" 
            stroke-width="2" 
            stroke-linecap="round" 
            stroke-linejoin="round"
          >
            <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
            <circle cx="12" cy="12" r="3"></circle>
          </svg>
        </button>

        <button 
          class="action-button copy-button"
          @click="handleCopyMessage"
          :title="copySuccess ? '已复制' : '复制'"
        >
          <svg 
            v-if="!copySuccess"
            xmlns="http://www.w3.org/2000/svg" 
            width="16" 
            height="16" 
            viewBox="0 0 24 24" 
            fill="none" 
            stroke="currentColor" 
            stroke-width="2" 
            stroke-linecap="round" 
            stroke-linejoin="round"
          >
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
          </svg>
          <svg 
            v-else
            xmlns="http://www.w3.org/2000/svg" 
            width="16" 
            height="16" 
            viewBox="0 0 24 24" 
            fill="none" 
            stroke="currentColor" 
            stroke-width="2" 
            stroke-linecap="round" 
            stroke-linejoin="round"
          >
            <polyline points="20 6 9 17 4 12"></polyline>
          </svg>
        </button>
        
        <!-- 重新生成按钮 - 仅在AI消息是最后一条且已生成完成时显示 -->
        <button 
          v-if="showRegenerateButton"
          class="action-button regenerate-button"
          @click="handleRegenerate"
          title="重新生成"
        >
          <svg 
            xmlns="http://www.w3.org/2000/svg" 
            width="16" 
            height="16" 
            viewBox="0 0 24 24" 
            fill="none" 
            stroke="currentColor" 
            stroke-width="2" 
            stroke-linecap="round" 
            stroke-linejoin="round"
          >
            <path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"/>
          </svg>
        </button>
      </div>
    </div>

</template>

<style scoped>
/* 文件下载链接样式 */
.file-download-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: rgba(102, 126, 234, 0.1);
  border-radius: 8px;
  color: var(--text-primary);
  text-decoration: none;
  transition: all 0.2s ease;
  border: 1px solid rgba(102, 126, 234, 0.2);
}

.file-download-link:hover {
  background-color: rgba(102, 126, 234, 0.2);
  transform: translateY(-1px);
}

.file-icon {
  font-size: 18px;
}

.file-name {
  font-weight: 500;
}

.download-text {
  font-size: 0.8em;
  color: var(--primary);
  margin-left: auto;
}
/* 消息气泡基础样式 */
.message-bubble {
  display: flex;
  gap: 12px;
  margin: 8px 0 4px 0;
  align-items: flex-start;
  position: relative;
  max-width: 85%;
  width: fit-content;
}

.message-bubble.user-message {
  flex-direction: row-reverse;
  margin-left: auto;
}

.message-bubble:not(.user-message) {
  margin-right: auto;
}

.message-avatar {
  flex-shrink: 0;
  margin-top: 4px;
}

.avatar-bg {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  color: white;
  font-weight: bold;
  font-size: 18px;
}

.assistant-avatar-bg {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border: 4px solid white;
}

.user-avatar-bg {
  background: linear-gradient(135deg, #6366f1 0%, #ec4899 100%);
  border: 4px solid white;
}

.avatar-icon {
  color: white;
  font-size: 18px;
}

.message-wrapper {
  flex: 1;
  min-width: 0;
  position: relative;
}

.message-content {
  padding: 14px 18px;
  border-radius: 18px;
  font-size: 14px;
  line-height: 1.6;
  overflow-wrap: break-word;
  transition: all 0.3s ease;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  width: 100%;
}

.user-message .message-content {
  background: rgba(255, 255, 255, 0.95);
  color: #2d3748;
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  border-top-right-radius: 4px;
}

.message-bubble:not(.user-message) .message-content {
  border-top-left-radius: 4px;
}

/* 思考状态样式 */
.message-content.thinking {
  color: #6b7280;
  font-style: italic;
  display: flex;
  align-items: center;
  gap: 12px;
  background-color: rgba(107, 114, 128, 0.1);
  backdrop-filter: blur(8px);
  transform-origin: left center;
  animation: appear 0.3s ease-out;
}

.thinking-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
}

.thinking-text {
  font-weight: 500;
}

.thinking-dots span {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background-color: #6b7280;
  animation: dot-jump 1.4s infinite;
}

.thinking-dots span:nth-child(1) { animation-delay: 0s; }
.thinking-dots span:nth-child(2) { animation-delay: 0.2s; }
.thinking-dots span:nth-child(3) { animation-delay: 0.4s; }

@keyframes dot-jump {
  0%, 80%, 100% { transform: translateY(0); opacity: 0.5; }
  40% { transform: translateY(-6px); opacity: 1; }
}

@keyframes appear {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* 消息底部样式 */
.message-footer {
  position: relative;
  margin-top: 0;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 28px;
  z-index: 1;
}

.user-message + .message-footer {
  justify-content: flex-end;
}

.message-bubble:not(.user-message) + .message-footer {
  justify-content: flex-start;
}

.timestamp {
  font-size: 11px;
  color: #a0aec0;
  z-index: 1;
}

/* 操作按钮样式 */
.message-actions {
  display: flex;
  gap: 8px;
  opacity: 0;
  transition: opacity 0.2s ease;
  background: rgba(255, 255, 255, 0.95);
  padding: 2px 8px;
  border-radius: 14px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  z-index: 2;
}

.user-message + .message-footer .message-actions {
  /* 样式已在 message-footer 中处理 */
}

.message-footer:hover .message-actions,
.message-actions.visible {
  opacity: 1;
}

.action-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background-color: rgba(255, 255, 255, 0.95);
  border-radius: 50%;
  cursor: pointer;
  color: #6b7280;
  transition: all 0.2s ease;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  position: relative;
}

.action-button:hover {
  background-color: white;
  color: #667eea;
  transform: scale(1.1);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
}

.action-button:active {
  transform: scale(0.98);
}

.regenerate-button {
  color: #6366f1;
}

.regenerate-button:hover {
  background-color: rgba(99, 102, 241, 0.1);
  color: #4f46e5;
}

.action-button svg {
  transition: transform 0.2s ease;
}

.action-button:hover svg {
  transform: scale(1.1);
}

.action-button::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  opacity: 0;
  transition: opacity 0.2s ease;
}

.action-button:hover::after {
  opacity: 1;
}

.preview-button:hover {
  color: #3b82f6;
}

.copy-button:hover {
  color: #10b981;
}

/* 选中状态 */
.message-bubble.selected .message-content {
  outline: 2px solid #667eea;
  outline-offset: 2px;
}
</style>

<style>
/* 全局 Markdown 样式 */
.message-content.markdown-body {
  line-height: 1.6;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  transition: opacity 0.3s ease;
}

.message-content.markdown-body p {
  margin: 0.8em 0;
}

/* 代码块容器 */
.message-content .code-block {
  position: relative;
  border-radius: 8px;
  margin: 16px 0;
  background-color: rgba(0, 0, 0, 0.05);
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}

/* 代码标题栏 */
.message-content .code-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: rgba(99, 102, 241, 0.1);
  color: #4f46e5;
  font-size: 14px;
  font-weight: 500;
  border-radius: 6px;
  transition: background-color 0.2s ease;
}

/* 标题栏左侧布局 */
.message-content .header-left {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 展开/收起按钮样式 */
.message-content .toggle-button {
  background: transparent;
  border: none;
  padding: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #555;
  transition: transform 0.2s ease;
  opacity: 0.7;
}

.message-content .toggle-button:hover {
  opacity: 1;
}

.message-content .toggle-button svg {
  transition: transform 0.2s ease;
}

/* 代码块收起状态 */
.message-content .hljs-pre:not(.expanded) {
  display: none;
}

.message-content .language-label {
  color: #666;
  font-weight: 500;
  text-transform: uppercase;
  font-size: 0.85em;
  letter-spacing: 0.5px;
}

/* 代码块按钮通用样式 */
.message-content .code-header button {
  background: rgba(255, 255, 255, 0.2);
  border: none;
  border-radius: 4px;
  padding: 4px 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
  transition: all 0.2s;
  color: #555;
  font-size: 13px;
}

.message-content .code-header button:hover {
  background: rgba(255, 255, 255, 0.3);
  color: #333;
}

.message-content .code-header:hover {
  background-color: rgba(99, 102, 241, 0.15);
}

.message-content .code-header button svg {
  width: 14px;
  height: 14px;
}

/* 运行按钮特殊样式 */
.message-content .run-button {
  background: rgba(52, 152, 219, 0.2) !important;
  color: #2980b9 !important;
  margin-right: 8px;
}

.message-content .run-button:hover {
  background: rgba(52, 152, 219, 0.3) !important;
  color: #2980b9 !important;
}

/* 用户消息中的运行按钮样式 */
.user-message .message-content .run-button {
  background: rgba(255, 255, 255, 0.2) !important;
  color: white !important;
}

.user-message .message-content .run-button:hover {
  background: rgba(255, 255, 255, 0.3) !important;
}

/* 代码块标题栏右侧布局 */
.message-content .header-right {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 复制成功状态 */
.message-content .copy-button.copied {
  background-color: #e8f5e9;
  color: #4CAF50;
}

.message-content .copied-text {
  font-size: 12px;
}

/* 代码内容区域 */
.message-content .hljs-pre {
  margin: 0;
  padding: 16px;
  overflow-x: auto;
  font-size: 14px;
  line-height: 1.5;
  background-color: rgba(0, 0, 0, 0.03);
}

.message-content .markdown-body code {
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 14px;
}

.message-content .markdown-body pre code {
  background: none;
  padding: 0;
}

/* Mermaid 图表样式 - 强制统一大小 */
.message-content .markdown-body .mermaid {
  background-color: white;
  padding: 16px;
  text-align: center;
  overflow: hidden; /* 改为hidden防止滚动条 */
  position: relative;
  width: 800px;
  min-width: 800px;
  max-width: 800px;
  margin: 0 auto;
  box-sizing: border-box;
}

/* 强制SVG图表固定尺寸 */
.message-content .markdown-body .mermaid svg {
  width: 100% !important;
  height: auto !important;
  max-height: 600px;
  display: block;
  margin: 0 auto;
}

/* Mermaid 加载占位符样式 */
.message-content .markdown-body .mermaid .mermaid-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background-color: #f8f9fa;
  border-radius: 4px;
  color: #6c757d;
  font-style: italic;
  margin: 10px 0;
  min-height: 60px;
  border: 1px dashed #dee2e6;
}

/* 当mermaid图表处于pending状态时隐藏原始代码 */
.message-content .markdown-body .mermaid[data-pending="true"] > :not(.mermaid-placeholder) {
  visibility: hidden;
  height: 0;
  overflow: hidden;
}

/* Mermaid 代码块特殊样式 */
.message-content .code-block .mermaid {
  margin: 0;
  box-shadow: none;
  border-radius: 0;
}

/* 确保 Mermaid 图表在代码块中正确显示 */
.message-content .code-block pre.hljs-pre.expanded .mermaid {
  display: block;
  width: 100%;
}

/* 其他 Markdown 元素样式 */
.message-content .markdown-body blockquote {
  border-left: 4px solid #ddd;
  padding: 0 0 0 16px;
  margin: 16px 0;
  color: #666;
}

.message-content .markdown-body table {
  border-collapse: collapse;
  width: 100%;
  margin: 16px 0;
}

.message-content .markdown-body th, 
.message-content .markdown-body td {
  border: 1px solid #ddd;
  padding: 8px;
  text-align: left;
}

.message-content .markdown-body th {
  background-color: #f8f8f8;
  font-weight: 600;
}

.message-content .markdown-body tr:nth-child(even) {
  background-color: #f9f9f9;
}

.message-content .markdown-body ul, 
.message-content .markdown-body ol {
  padding-left: 24px;
  margin: 12px 0;
}

.message-content .markdown-body li {
  margin-bottom: 6px;
}

.message-content .markdown-body a {
  color: #0366d6;
  text-decoration: none;
}

.message-content .markdown-body a:hover {
  text-decoration: underline;
}

/* 用户消息中的特殊样式覆盖 */
.user-message .message-content.markdown-body a {
  color: white;
  text-decoration: underline;
}

.user-message .message-content .code-block {
  background-color: rgba(255, 255, 255, 0.1);
}

.user-message .message-content .code-header {
  background-color: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.9);
  border-radius: 6px;
}

.user-message .message-content .hljs-pre {
  background-color: rgba(255, 255, 255, 0.1);
}

.user-message .message-content .copy-button {
  color: white;
  background: rgba(255, 255, 255, 0.2);
}

.user-message .message-content .copy-button:hover {
  background: rgba(255, 255, 255, 0.3);
}

.user-message .message-content .language-label {
  color: rgba(255, 255, 255, 0.8);
}

/* 思考内容样式 */
.think-container {
  margin-bottom: 16px;
  border-radius: 8px;
  overflow: hidden;
}

.think-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: rgba(99, 102, 241, 0.1);
  color: #4f46e5;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  border-radius: 6px;
  transition: background-color 0.2s ease;
}

.think-header:hover {
  background-color: rgba(99, 102, 241, 0.15);
}

.think-header svg {
  transition: transform 0.2s ease;
}

.think-content {
  background-color: rgba(243, 244, 246, 0.8);
  border: 1px solid rgba(209, 213, 219, 0.5);
  border-radius: 6px;
  margin-top: 8px;
  padding: 12px;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-x: auto;
  max-height: 400px;
  overflow-y: auto;
}

.user-message .think-header {
  background-color: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.9);
}

.user-message .think-content {
  background-color: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.9);
}

/* 文件下载链接样式 */
.file-download {
  margin: 8px 0;
}

.file-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background-color: rgba(99, 102, 241, 0.1);
  color: #4f46e5;
  border-radius: 8px;
  text-decoration: none;
  font-weight: 500;
  transition: background-color 0.2s ease;
}

/* 引用文件列表样式 */
.source-files-container {
  margin-top: 16px;
  border-radius: 8px;
  overflow: hidden;
}

.source-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: rgba(99, 102, 241, 0.1);
  color: #4f46e5;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  border-radius: 6px;
  transition: background-color 0.2s ease;
}

.source-header:hover {
  background-color: rgba(99, 102, 241, 0.15);
}

.source-header svg {
  transition: transform 0.2s ease;
}

.source-count {
  color: #6b7280;
  font-size: 12px;
  margin-left: 4px;
}

.source-list {
  background-color: rgba(243, 244, 246, 0.8);
  border: 1px solid rgba(209, 213, 219, 0.5);
  border-radius: 6px;
  margin-top: 8px;
  padding: 8px;
}

.source-item {
  margin-bottom: 8px;
}

.source-item:last-child {
  margin-bottom: 0;
}

.file-download-link {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background-color: white;
  border: 1px solid rgba(209, 213, 219, 0.5);
  border-radius: 6px;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.file-download-link:hover {
  background-color: rgba(243, 244, 246, 1);
}

.file-icon {
  font-size: 16px;
}

.file-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
}

.download-text {
  color: #4f46e5;
  font-size: 12px;
  font-weight: 500;
}

.user-message .source-header {
  background-color: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.9);
}

.user-message .source-count {
  color: rgba(255, 255, 255, 0.6);
}

.user-message .source-list {
  background-color: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.1);
}

.user-message .file-download-link {
  background-color: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.9);
}

.user-message .file-download-link:hover {
  background-color: rgba(255, 255, 255, 0.15);
}

.user-message .download-text {
  color: rgba(255, 255, 255, 0.8);
}

.file-link:hover {
  background-color: rgba(99, 102, 241, 0.2);
  text-decoration: none;
}

.user-message .file-link {
  background-color: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.9);
}

.user-message .file-link:hover {
  background-color: rgba(255, 255, 255, 0.2);
}
</style>    